package org.ucas.faker.web.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.ucas.faker.web.utils.model.RawPatent;
import org.ucas.faker.web.dao.DepotDao;
import org.ucas.faker.web.dao.patents.MetaDao;
import org.ucas.faker.web.dao.RecordDao;
import org.ucas.faker.web.dao.UserDao;
import org.ucas.faker.web.entity.Depot;
import org.ucas.faker.web.entity.Record;
import org.ucas.faker.web.exceptions.BadRequestException;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Transactional
public class DepotService {

  @Autowired
  private DepotDao depotDao;

  @Autowired
  private RecordDao recordDao;

  @Autowired
  private MetaDao metaDao;

  @Autowired
  private UserDao userDao;

  public Depot create(long userId, String name) {
    Depot depot = null;
    if(name != null) depot = findByName(userId,name);
    if(depot != null) throw BadRequestException.DEPOT_ALREADY_EXISTS;
    depot = new Depot();
    depot.setOwner(userId);
    depot.setName(name);
    if(name == null) depot.setDeleted(true);
    return depotDao.save(depot);
  }

  public Depot load(long depotId) {
    return depotDao.findOne(depotId);
  }

  public Depot findByName(long userId, String name) {
    return depotDao.findByOwnerAndName(userId,name);
  }

  public Long mainDepotId() {
    return depotDao.findByOwnerAndName(userDao.findByAccount("root").getId(),"main").getId();
  }

  public Depot persist(Depot depot) {
    depot.setVersion(depot.getVersion() + 1);
    return depotDao.save(depot);
  }

  public List<Depot> list(long userId) {
    return depotDao.findByOwner(userId);
  }

  public void delete(long depotId) {
    depotDao.delete(depotId);
  }

  public void destroy(long depotId) {
    recordDao.clear(depotId);
    depotDao.destroy(depotId);
  }

  public Page<Depot> page(Long userId,Integer pageNumber, Integer pageSize) {
    if(pageNumber == null) pageNumber = 1;
    if(pageSize == null) pageSize = 50;

    PageRequest pageRequest = new PageRequest(pageNumber - 1, pageSize,null);
    Page<Depot> depots;
    if(userId!=null) depots = depotDao.pageByOwner(userId,pageRequest);
    else depots = depotDao.pageAll(pageRequest);

    return depots;
  }

  public void addPatents(long depotId, List<Long> patents, Integer selected) {
    if(selected == null) selected = 1;
    for(Long patentId : patents) {
      if(patentId == null || !metaDao.exists(patentId)) continue;;
      Record r = recordDao.findByDepotIdAndPatentId(depotId,patentId);
      if(r == null) r = new Record(depotId,patentId);
      r.setSelected(selected);
      recordDao.save(r);
    }
    depotDao.incVersion(depotId);
  }

  public void save(Depot depot) {
	  depotDao.save(depot);
  }
  
  public void addPatents(List<RawPatent> patents, long depotId, Integer selected) {
    List<Long> ids = patents.stream().map(p->p.id).filter(Objects::nonNull).collect(Collectors.toList());
    addPatents(depotId,ids,selected);
  }

  public void addPatents(List<RawPatent> patents, long depotId) {
    addPatents(patents,depotId,1);
  }

  public void addPatents(long depotId, List<Long> patents) {
    addPatents(depotId,patents,1);
  }

  public void removePatents(long depotId, List<Long> patents) {
    recordDao.removeBatch(depotId,patents);
    depotDao.incVersion(depotId);
  }

  public void removePatents(List<RawPatent> patents, long depotId) {
    List<Long> ids = patents.stream().map(p->p.id).filter(Objects::nonNull).collect(Collectors.toList());
    removePatents(depotId,ids);
  }

  public void selectPatents(long id, long depotId, int target) {
    recordDao.updateSelected(depotId,id,target);
    depotDao.incVersion(depotId);
  }

  public void selectPatents(List<Long> ids, long depotId, int target) {
    recordDao.updateSelected(depotId,ids,target);
    recordDao.flush();
    depotDao.incVersion(depotId);
  }

  public long currentVersion(long depotId) {
    return depotDao.curVersion(depotId);
  }

  public Long countSelect(long depotId) {
    return recordDao.countSelect(depotId,1);
  }
  
  public Long countByDepotId(long depotId) {
	  return recordDao.countByDepotId(depotId);
  }
}
